# -*- coding: utf-8 -*-
"""
Created on Mon Jun  5 10:29:48 2023

@author: ZHOU
"""

import gpx_function as gf
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
import os
import matplotlib.pyplot as plot
import threading

class GPXEditor:
    def __init__(self, root):
        self.root = root
        self.root.title("GPX文件编辑器")
        self.root.geometry("900x750")
        self.center_window(self.root)

        self.gpx_file = None
        self.gpx_data = None
        self.secondary_gpx_file = None  # 新增次级文件属性
        self.secondary_gpx_data = None

        self.gpx_fig = None
        self.secondary_fig = None
        
        # 添加子窗口跟踪列表
        self.trace_windows = []  # 存储轨迹图窗口
        self.active_threads = []  # 存储活动线程

        self.create_widgets()

        # 绑定主窗口关闭事件
        self.root.protocol("WM_DELETE_WINDOW", self.on_main_window_close)

    def on_main_window_close(self):
        """关闭主窗口时的清理操作"""
        # 关闭所有轨迹图子窗口
        for window in self.trace_windows:
            try:
                window.destroy()
            except:
                pass
        
        # 关闭所有matplotlib图形
        if self.gpx_fig:
            plot.close(self.gpx_fig)
        if self.secondary_fig:
            plot.close(self.secondary_fig)
        
        # 清理线程
        for thread in self.active_threads:
            if thread.is_alive():
                # 设置线程为守护线程，主线程退出时会自动结束
                thread.daemon = True
        
        # 关闭主窗口
        self.root.destroy()

    def center_window(self, window):
        """使窗口居中显示"""
        window.update_idletasks()
        width = window.winfo_width()
        height = window.winfo_height()
        x = (window.winfo_screenwidth() // 2) - (width // 2)
        y = (window.winfo_screenheight() // 2) - (height // 2)
        window.geometry(f"{width}x{height}+{x}+{y}")
                        
    def create_widgets(self):
        # 文件选择区域
        file_frame = tk.LabelFrame(self.root, text="主文件选择", padx=10, pady=10)
        file_frame.pack(fill="x", padx=10, pady=5)
        
        tk.Button(file_frame, text="选择GPX文件", command=self.select_gpx_file).grid(row=0, column=0, padx=5, pady=5)
        tk.Button(file_frame, text="取消选择", command=self.clear_gpx_file, width=10).grid(row=0, column=1, padx=5, pady=5)
        
        # 添加轨迹图按钮
        self.trace_btn1 = tk.Button(file_frame, text="轨迹图1", command=lambda: self.open_trace_window(1), width=10)
        self.trace_btn1.grid(row=0, column=2, padx=5, pady=5)

        self.trace_btn2 = tk.Button(file_frame, text="轨迹图2", command=lambda: self.open_trace_window(2), width=10)
        self.trace_btn2.grid(row=0, column=3, padx=5, pady=5)
        
        self.file_label = tk.Label(file_frame, text="未选择文件")
        self.file_label.grid(row=1, column=0, columnspan=2, padx=5, pady=5, sticky="w")
        
        self.full_path_label = tk.Label(file_frame, text="", fg="gray", font=("Arial", 8))
        self.full_path_label.grid(row=2, column=0, columnspan=2, padx=5, pady=2, sticky="w")
        
        # 输出路径设置
        output_frame = tk.LabelFrame(self.root, text="输出设置", padx=10, pady=10)
        output_frame.pack(fill="x", padx=10, pady=5)
        
        tk.Label(output_frame, text="输出文件名:").grid(row=0, column=0, padx=5, pady=5)
        self.output_entry = tk.Entry(output_frame, width=50)
        self.output_entry.grid(row=0, column=1, padx=5, pady=5)
        tk.Button(output_frame, text="浏览", command=self.select_output_file).grid(row=0, column=2, padx=5, pady=5)
        
        tk.Label(output_frame, text="SRT文件名:").grid(row=1, column=0, padx=5, pady=5)
        self.srt_entry = tk.Entry(output_frame, width=50)
        self.srt_entry.grid(row=1, column=1, padx=5, pady=5)
        tk.Button(output_frame, text="浏览", command=self.select_srt_file).grid(row=1, column=2, padx=5, pady=5)
        
        # 功能按钮区域 - 重新分组
        main_func_frame = tk.Frame(self.root)
        main_func_frame.pack(fill="both", expand=True, padx=10, pady=5)
        
        # 第一组：扩展数据操作
        ext_data_frame = tk.LabelFrame(main_func_frame, text="扩展数据操作", padx=10, pady=10)
        ext_data_frame.pack(fill="both", expand=True, side="left", padx=5, pady=5)
        
        ext_buttons = [
            ("生成心率数据", lambda: self.make_data_random("心率")),
            ("修改心率数据", lambda: self.change_data_type("心率")),
            ("生成踏频数据", lambda: self.make_data_random("踏频")),
            ("修改踏频数据", lambda: self.change_data_type("踏频")),
            ("生成功率数据", lambda: self.make_data_random("功率")),
            ("修改功率数据", lambda: self.change_data_type("功率")),
            ("生成距离数据", lambda: self.make_data_random("距离")),
            ("修改距离数据", lambda: self.change_data_type("距离")),
            ("生成速度数据", lambda: self.make_data_random("速度")),
            ("修改速度数据", lambda: self.change_data_type("速度")),
            ("清理扩展数据", self.clean_data)
        ]
        
        for i, (text, command) in enumerate(ext_buttons):
            btn = tk.Button(ext_data_frame, text=text, command=command, width=15)
            btn.grid(row=i//2, column=i%2, padx=5, pady=5, sticky="ew")
        
        # 自定义关键词功能
        custom_frame = tk.Frame(ext_data_frame)
        custom_frame.grid(row=6, column=0, columnspan=2, sticky="ew", padx=5, pady=5)
        
        tk.Label(custom_frame, text="自定义关键词:").pack(side="left")
        self.custom_keyword_entry = tk.Entry(custom_frame, width=10)
        self.custom_keyword_entry.pack(side="left", padx=2)
        
        tk.Button(custom_frame, text="修改数据", command=self.change_custom_data, width=8).pack(side="left", padx=2)
        tk.Button(custom_frame, text="生成数据", command=self.make_custom_data, width=8).pack(side="left", padx=2)

        # 第二组：基础数据操作
        base_data_frame = tk.LabelFrame(main_func_frame, text="基础数据操作", padx=10, pady=10)
        base_data_frame.pack(fill="both", expand=True, side="left", padx=5, pady=5)
        
        base_buttons = [
            ("修改坐标", self.change_location),
            ("随机偏移坐标", self.change_location_random),
            ("修改海拔", self.change_ele),
            ("渐进爬升", self.change_ele_climb),
            ("生成时间序列", self.make_time),
            ("调整时间轴", self.change_time),
            ("读取当前缓存", self.read_gpx),  # 移到基础数据操作
            ("计算速度", self.calculate_velocity),  # 移到基础数据操作
            ("整合数据", self.integrate_data),  # 新增整合数据按钮
            ("轨迹极值点获取", self.find_poles)  # 新增极值点获取按钮
        ]
        
        for i, (text, command) in enumerate(base_buttons):
            btn = tk.Button(base_data_frame, text=text, command=command, width=15)
            btn.grid(row=i//2, column=i%2, padx=5, pady=5, sticky="ew")
        
        # 极值点显示区域
        pole_frame = tk.Frame(base_data_frame)
        pole_frame.grid(row=5, column=0, columnspan=2, sticky="ew", padx=5, pady=5)
        
        self.pole_texts = {}
        pole_names = ["最北点", "最南点", "最东点", "最西点", "起点", "终点"]
        
        for i, name in enumerate(pole_names):
            tk.Label(pole_frame, text=name + ":").grid(row=i, column=0, sticky="w", padx=2, pady=2)
            self.pole_texts[name] = tk.Text(pole_frame, height=1, width=20, font=("Arial", 8))
            self.pole_texts[name].insert("1.0", "未获取")
            self.pole_texts[name].config(state="disabled", fg="gray")
            self.pole_texts[name].grid(row=i, column=1, sticky="w", padx=2, pady=2)

        # 第三组：文件操作
        file_ops_frame = tk.LabelFrame(main_func_frame, text="文件操作", padx=10, pady=10)
        file_ops_frame.pack(fill="both", expand=True, side="left", padx=5, pady=5)
        
        # GPX标志选择
        gpx_flag_frame = tk.Frame(file_ops_frame)
        gpx_flag_frame.pack(fill="x", pady=5)
        
        tk.Label(gpx_flag_frame, text="GPX类型:").pack(side="left")
        self.gpx_flag_var = tk.StringVar(value="COROS")
        self.gpx_flag_combo = ttk.Combobox(gpx_flag_frame, textvariable=self.gpx_flag_var, 
                                         values=list(gf.GPX_FLAGS.keys()), width=8)
        self.gpx_flag_combo.pack(side="left", padx=2)
        tk.Button(gpx_flag_frame, text="修改标志", command=self.change_gpx_flag, width=10).pack(side="left")
        
        # 文件操作按钮
        file_ops_buttons = [
            ("生成SRT", self.generate_srt),
            ("生成最终SRT", self.generate_final_srt),  # 新增生成最终SRT按钮
            ("复制轨迹段", self.copy_gpx),
            ("保存缓存文件", self.save_files)
        ]
        
        for i, (text, command) in enumerate(file_ops_buttons):
            btn = tk.Button(file_ops_frame, text=text, command=command, width=15)
            btn.pack(pady=3)
        
        # 次级文件选择和拼接功能
        secondary_frame = tk.Frame(file_ops_frame)
        secondary_frame.pack(fill="x", pady=5)
        
        tk.Button(secondary_frame, text="选择次级GPX文件", command=self.select_secondary_file, width=15).pack(pady=3)
        tk.Button(secondary_frame, text="取消选择次级文件", command=self.clear_secondary_file, width=15).pack(pady=3)
        
        self.secondary_file_label = tk.Label(secondary_frame, text="未选择次级文件", fg="gray")
        self.secondary_file_label.pack(pady=2)
        
        self.secondary_full_path_label = tk.Label(secondary_frame, text="", fg="gray", font=("Arial", 7))
        self.secondary_full_path_label.pack(pady=1)
        
        tk.Button(secondary_frame, text="拼接文件", command=self.splice_files, width=15).pack(pady=3)

        # 状态显示
        self.status_label = tk.Label(self.root, text="就绪", bd=1, relief=tk.SUNKEN, anchor=tk.W)
        self.status_label.pack(side=tk.BOTTOM, fill=tk.X)

    def open_trace_window(self, window_num):
        """多线程打开轨迹图窗口"""
        # 禁用按钮
        if window_num == 1:
            if not self.gpx_fig:
                messagebox.showwarning("警告", "请先读取主GPX文件生成轨迹图")
                self.trace_btn1.config(state="normal")
                return
        else:
            if not self.secondary_fig:
                messagebox.showwarning("警告", "请先读取次GPX文件生成轨迹图")
                self.trace_btn2.config(state="normal")
                return
        
        # 禁用按钮
        if window_num == 1:
            self.trace_btn1.config(state="disabled")
        else:
            self.trace_btn2.config(state="disabled")
        
        # 使用多线程打开窗口
        thread = threading.Thread(target=self._show_trace_window, args=(window_num,))
        thread.daemon = True
        self.active_threads.append(thread)  # 跟踪线程
        thread.start()

    def _show_trace_window(self, window_num):
        """显示轨迹图窗口"""
        try:
            # 创建子窗口
            sub_window = tk.Toplevel(self.root)
            sub_window.title(f"轨迹图{window_num}")
            sub_window.geometry("1440x720")
            self.center_window(sub_window)
            
            # 添加到跟踪列表
            window_info = {
                'window': sub_window,
                'number': window_num,
                'thread': threading.current_thread()
            }
            self.trace_windows.append(window_info)

            # 创建顶部按钮框架
            button_frame = tk.Frame(sub_window)
            button_frame.pack(fill=tk.X, padx=10, pady=5)
            
            # 添加刷新按钮
            refresh_btn = tk.Button(button_frame, text="刷新图像", command=lambda: self.refresh_trace_figure(sub_window, window_num))
            refresh_btn.pack(side=tk.RIGHT, padx=5)

            # 创建画布框架
            canvas_frame = tk.Frame(sub_window)
            canvas_frame.pack(fill=tk.BOTH, expand=True)
            
            # 初始显示图像
            self.display_trace_figure(canvas_frame, window_num)
            
            # 窗口关闭时重新启用按钮
            def on_closing():
                if window_num == 1:
                    self.trace_btn1.config(state="normal")
                else:
                    self.trace_btn2.config(state="normal")
                
                # 从跟踪列表中移除
                for i, win_info in enumerate(self.trace_windows):
                    if win_info['window'] == sub_window:
                        self.trace_windows.pop(i)
                        break
                
                # 从活动线程中移除
                current_thread = threading.current_thread()
                for i, thread in enumerate(self.active_threads):
                    if thread == current_thread:
                        self.active_threads.pop(i)
                        break

                sub_window.destroy()
            
            sub_window.protocol("WM_DELETE_WINDOW", on_closing)
            
        except Exception as e:
            messagebox.showerror("错误", f"打开轨迹图窗口失败: {e}")
            # 出错时也重新启用按钮
            try:
                if window_num == 1:
                    self.trace_btn1.config(state="normal")
                else:
                    self.trace_btn2.config(state="normal")
            except:
                pass

    def refresh_trace_figure(self, sub_window, window_num):
        """刷新轨迹图 - 关闭窗口并重新打开"""
        try:
            # 重新读取对应的GPX数据并生成图形
            if window_num == 1 and self.gpx_data:
                gpx_dict = gf.read_gpx(self.gpx_data)
                if len(gpx_dict['num']):
                    if self.gpx_fig:
                        plot.close(self.gpx_fig)  # 关闭旧图形
                    self.gpx_fig = gf.show_gpx_dict(gpx_dict)
            elif window_num == 2 and self.secondary_gpx_data:
                gpx_dict = gf.read_gpx(self.secondary_gpx_data)
                if len(gpx_dict['num']):
                    if self.secondary_fig:
                        plot.close(self.secondary_fig)  # 关闭旧图形
                    self.secondary_fig = gf.show_gpx_dict(gpx_dict)
            
            # 关闭当前窗口
            sub_window.destroy()
            
            # 重新打开轨迹图窗口
            self.open_trace_window(window_num)
            
        except Exception as e:
            messagebox.showerror("错误", f"刷新图像失败: {e}")

    def display_trace_figure(self, parent_frame, window_num):
        """在指定父框架中显示轨迹图"""
        try:
            # 根据window_num决定显示哪个图
            if window_num == 1 and self.gpx_fig:
                # 显示主轨迹图
                from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
                
                canvas = FigureCanvasTkAgg(self.gpx_fig, master=parent_frame)
                canvas.draw()
                canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
            elif window_num == 2 and self.secondary_fig:
                # 显示次级轨迹图
                from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
                
                canvas = FigureCanvasTkAgg(self.secondary_fig, master=parent_frame)
                canvas.draw()
                canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
            else:
                # 如果没有对应的图形，显示提示信息
                if window_num == 1:
                    tk.Label(parent_frame, text="请先读取主GPX文件生成轨迹图", fg="red").pack(pady=50)
                else:
                    tk.Label(parent_frame, text="请先选择次级GPX文件生成轨迹图", fg="red").pack(pady=50)
        except Exception as e:
            messagebox.showerror("错误", f"显示图像失败: {e}")

    def find_poles(self):
        """获取轨迹极值点和起终点坐标"""
        if not self.gpx_data:
            messagebox.showwarning("警告", "请先选择并加载GPX文件")
            return
            
        try:
            # 获取四个极值点
            poles = gf.find_pole(self.gpx_data)
            # 获取起终点坐标
            start_end = gf.find_start_end_location(self.gpx_data)
            
            # 更新显示
            pole_names = ["最北点", "最南点", "最东点", "最西点"]
            for i, name in enumerate(pole_names):
                lat, lon = poles[i]
                self.pole_texts[name].config(state="normal")
                self.pole_texts[name].delete("1.0", tk.END)
                self.pole_texts[name].insert("1.0", f"{lat:.6f}, {lon:.6f}")
                self.pole_texts[name].config(state="disabled", fg="black")
            
            # 更新起终点显示
            self.pole_texts["起点"].config(state="normal")
            self.pole_texts["起点"].delete("1.0", tk.END)
            self.pole_texts["起点"].insert("1.0", f"{start_end[0][0]:.6f}, {start_end[0][1]:.6f}")
            self.pole_texts["起点"].config(state="disabled", fg="blue")
            
            self.pole_texts["终点"].config(state="normal")
            self.pole_texts["终点"].delete("1.0", tk.END)
            self.pole_texts["终点"].insert("1.0", f"{start_end[1][0]:.6f}, {start_end[1][1]:.6f}")
            self.pole_texts["终点"].config(state="disabled", fg="red")
            
            self.status_label.config(text="极值点和起终点坐标获取完成")
            
        except Exception as e:
            messagebox.showerror("错误", f"获取极值点失败: {e}")
            self.status_label.config(text="极值点获取失败")

    def integrate_data(self):
        """整合数据：先计算速度，再将速度和弧长数据写入GPX"""
        if not self.gpx_data:
            messagebox.showwarning("警告", "请先选择并加载GPX文件")
            return
            
        try:
            # 先进行速度计算
            gpx_dict = gf.read_gpx(self.gpx_data)
            data_dict = gf.calculate_velocity(gpx_dict)
            if data_dict[0] is None:
                messagebox.showwarning("警告", "速度计算失败")
                return
            data_dict = data_dict[0]

            # 将速度数据写入GPX
            self.gpx_data = gf.make_data_list(self.gpx_data, data_dict["velocity"], "velocity")            
            self.gpx_data = gf.make_data_list(self.gpx_data, data_dict["arclength"], "arclength")
            
            messagebox.showinfo("整合数据", "数据整合完成！已将速度和弧长数据写入GPX文件")
            self.status_label.config(text="数据整合完成")
            
        except Exception as e:
            messagebox.showerror("错误", f"数据整合失败: {e}")
            self.status_label.config(text="数据整合失败")
            
    def generate_final_srt(self):
        if not self.gpx_data:
            messagebox.showwarning("警告", "请先选择并加载GPX文件")
            return
            
        try:
            # 先进行速度计算
            gpx_dict = gf.read_gpx(self.gpx_data)
            data_dict = gf.calculate_velocity(gpx_dict)
            if data_dict[0] is None:
                messagebox.showwarning("警告", "速度计算失败")
                return
            data_dict = data_dict[0]
            # 使用速度计算结果生成SRT

            srt_list = gf.gpx_dict_to_srt(data_dict)
            
            srt_path = self.srt_entry.get()

            if srt_path:
                gf.save_lines(srt_list, srt_path)
                messagebox.showinfo("最终SRT生成", f"最终SRT文件已保存: {srt_path}\n包含速度计算结果")
                self.status_label.config(text="最终SRT生成完成")
            else:
                messagebox.showwarning("警告", "请先设置SRT输出路径")
                
        except Exception as e:
            messagebox.showerror("错误", f"最终SRT生成失败: {e}")
            self.status_label.config(text="最终SRT生成失败")

    def change_data_type(self, data_type):
        mapping = {"心率": "heartrate", "踏频": "cadence", "功率": "power", "距离": "distance", "速度": "speed"}
        keyword = mapping[data_type]
        self.show_param_dialog(f"修改{data_type}数据", [("调整系数", "1.0")], 
                              lambda params: gf.change_data(self.gpx_data, float(params[0]), keyword))
        
    def change_custom_data(self):
        keyword = self.custom_keyword_entry.get().strip()
        if not keyword:
            messagebox.showwarning("警告", "请输入自定义关键词")
            return
        
        self.show_param_dialog(f"修改{keyword}数据", [("系数", "1")], 
                              lambda params: gf.change_data(self.gpx_data, float(params[0]), keyword))
    
    def make_custom_data(self):
        keyword = self.custom_keyword_entry.get().strip()
        if not keyword:
            messagebox.showwarning("警告", "请输入自定义关键词")
            return
        
        self.show_param_dialog(f"生成{keyword}数据", [("平均值", "100"), ("波动范围", "20"), ("系数", "1")], 
                              lambda params: gf.make_data_random(self.gpx_data, float(params[0]), float(params[1]), keyword, float(params[2])))
        
    def change_gpx_flag(self):
        if not self.gpx_data:
            messagebox.showwarning("警告", "请先选择并加载GPX文件")
            return
        
        selected_flag = self.gpx_flag_var.get()
        if selected_flag in gf.gf.GPX_FLAGS:
            self.gpx_data = gf.change_gpx_flag(self.gpx_data, gf.gf.GPX_FLAGS[selected_flag])
            self.status_label.config(text=f"GPX标志已修改为: {selected_flag}")
        else:
            messagebox.showerror("错误", "选择的GPX类型不存在")
            
    def clear_gpx_file(self):
        if self.gpx_fig:
            plot.close(self.gpx_fig)
        self.gpx_fig = None        
        self.gpx_file = None
        self.gpx_data = None
        self.file_label.config(text="未选择文件")
        self.full_path_label.config(text="")
        self.output_entry.delete(0, tk.END)
        self.srt_entry.delete(0, tk.END)
        self.status_label.config(text="已取消文件选择")
        
    def select_gpx_file(self):
        self.clear_gpx_file()
        file_path = filedialog.askopenfilename(
            title="选择GPX文件",
            filetypes=[("GPX files", "*.gpx"), ("All files", "*.*")]
        )
        if file_path:
            self.gpx_file = file_path
            self.file_label.config(text=os.path.basename(file_path))
            self.full_path_label.config(text=file_path)
            
            # 自动设置输出文件名，保持与选择文件相同的目录
            base_name = os.path.splitext(os.path.basename(file_path))[0]
            file_dir = os.path.dirname(file_path)
            
            self.output_entry.delete(0, tk.END)
            self.output_entry.insert(0, os.path.join(file_dir, f"{base_name}_new.gpx"))
            
            self.srt_entry.delete(0, tk.END)
            self.srt_entry.insert(0, os.path.join(file_dir, f"{base_name}_new.srt"))
            
            self.load_gpx_data()

            self.status_label.config(text="文件选择成功")

            self.read_gpx()
    
    def select_output_file(self):
        if self.gpx_file:
            initial_file = self.output_entry.get() or "output.gpx"
            file_path = filedialog.asksaveasfilename(
                title="选择输出GPX文件",
                initialfile=initial_file,
                filetypes=[("GPX files", "*.gpx"), ("All files", "*.*")]
            )
            if file_path:
                self.output_entry.delete(0, tk.END)
                self.output_entry.insert(0, file_path)

    def clear_secondary_file(self):
        if self.secondary_fig:
            plot.close(self.secondary_fig)
        self.secondary_fig = None
        self.secondary_gpx_file = None
        self.secondary_gpx_data = None
        self.secondary_file_label.config(text="未选择次级文件")
        self.secondary_full_path_label.config(text="")
        self.status_label.config(text="已取消次级文件选择")

    def select_secondary_file(self):
        self.clear_secondary_file()
        file_path = filedialog.askopenfilename(
            title="选择次级GPX文件",
            filetypes=[("GPX files", "*.gpx"), ("All files", "*.*")]
        )
        if file_path:
            self.secondary_gpx_file = file_path
            self.secondary_file_label.config(text=os.path.basename(file_path))
            self.secondary_full_path_label.config(text=file_path)
            
            try:
                with open(self.secondary_gpx_file, 'r', encoding="utf-8") as f:
                    self.secondary_gpx_data = f.readlines()
                self.status_label.config(text="次级文件加载成功")
            except Exception as e:
                messagebox.showerror("错误", f"读取文件失败: {e}")
                self.status_label.config(text="次级文件读取失败")

            self.status_label.config(text="次级文件选择成功")

            if self.secondary_gpx_data:
                gpx_dict = gf.read_gpx(self.secondary_gpx_data)
                if len(gpx_dict['num']):
                    self.secondary_fig = gf.show_gpx_dict(gpx_dict)
                    if self.secondary_fig:
                        self.status_label.config(text="次级轨迹图已生成，可点击轨迹图2按钮查看")
               
    def splice_files(self):
        if not self.gpx_data:
            messagebox.showwarning("警告", "请先选择并加载主GPX文件")
            return
            
        if not self.secondary_gpx_file:
            messagebox.showwarning("警告", "请先选择次级GPX文件")
            return
            
        try:
            if self.secondary_gpx_data:
                # 调用拼接函数
                self.gpx_data = gf.splice_gpx(self.gpx_data, self.secondary_gpx_data)
                self.status_label.config(text="文件拼接完成")
                messagebox.showinfo("成功", "GPX文件拼接完成")
                
        except Exception as e:
            messagebox.showerror("错误", f"文件拼接失败: {e}")
            self.status_label.config(text="文件拼接失败")

    def select_srt_file(self):
        if self.gpx_file:
            initial_file = self.srt_entry.get() or "output.srt"
            file_path = filedialog.asksaveasfilename(
                title="选择输出SRT文件",
                initialfile=initial_file,
                filetypes=[("SRT files", "*.srt"), ("All files", "*.*")]
            )
            if file_path:
                self.srt_entry.delete(0, tk.END)
                self.srt_entry.insert(0, file_path)
    
    def load_gpx_data(self):
        if self.gpx_file:
            try:
                with open(self.gpx_file, 'r', encoding="utf-8") as f:
                    self.gpx_data = f.readlines()
                self.status_label.config(text="GPX文件加载成功")
            except Exception as e:
                messagebox.showerror("错误", f"读取文件失败: {e}")
                self.status_label.config(text="文件读取失败")
    
    def change_location(self):
        self.show_param_dialog("修改坐标", [("纬度增量", "0.0"), ("经度增量", "0.0")], 
                              lambda params: gf.change_location(self.gpx_data, float(params[0]), float(params[1])))
    
    def change_location_random(self):
        self.gpx_data = gf.change_location_random(self.gpx_data)
        self.status_label.config(text="坐标随机偏移完成")
    
    def change_ele(self):
        self.show_param_dialog("修改海拔", [("系数", "1"), ("增加值", "0")], 
                              lambda params: gf.change_ele(self.gpx_data, int(params[0]), int(params[1])))
    
    def change_ele_climb(self):
        self.show_param_dialog("渐进爬升", [("递增系数", "1"), ("初始海拔", "100")], 
                              lambda params: gf.change_ele_climb(self.gpx_data, int(params[0]), int(params[1])))
    
    def make_time(self):
        self.show_param_dialog("生成时间序列", [("时间间隔系数", "1"), ("起始时间", "2023-01-01T00:00:00Z")], 
                              lambda params: gf.make_time(self.gpx_data, int(params[0]), params[1]))
    
    def clean_data(self):
        self.show_param_dialog("清理数据", [("关键字", "extensions")], 
                              lambda params: gf.clean_data(self.gpx_data, params[0]))
    
    def change_time(self):
        self.show_param_dialog("调整时间轴", [("时间缩放系数", "1.0"), ("时间偏移量(秒)", "0")], 
                              lambda params: gf.change_time(self.gpx_data, float(params[0]), int(params[1])))
    
    def copy_gpx(self):
        self.show_param_dialog("复制轨迹段", [("复制次数", "3"), ("随机偏移(0/1)", "0")], 
                              lambda params: gf.copy_gpx(self.gpx_data, int(params[0]), int(params[1])))
    
    def make_data_random(self, data_type):
        mapping = {"心率": "heartrate", "踏频": "cadence", "功率": "power", "距离": "distance", "速度": "speed"}
        keyword = mapping[data_type]
        self.show_param_dialog(f"生成{data_type}数据", [("平均值", "120"), ("波动范围", "20"), ("系数", "1")], 
                              lambda params: gf.make_data_random(self.gpx_data, float(params[0]), float(params[1]), keyword , float(params[2])))
    
    def read_gpx(self):
        if self.gpx_data:
            gpx_dict = gf.read_gpx(self.gpx_data)
            if len(gpx_dict['num']):
                self.gpx_fig = gf.show_gpx_dict(gpx_dict)
                if self.gpx_fig:
                    self.status_label.config(text="轨迹图已生成，可点击轨迹图按钮查看")
    
    def calculate_velocity(self):
        try:
            if self.gpx_data:
                gpx_dict = gf.read_gpx(self.gpx_data)
                data_dict = gf.calculate_velocity(gpx_dict)
                if data_dict[0] is None:
                    messagebox.showwarning("警告", "速度计算失败")
                    return
                
                messagebox.showinfo("速度计算", f"速度计算完成，\n总里程： {data_dict[1]:.2f} km\n总用时：{data_dict[2]:.2f} h\n平均速度: {data_dict[3]:.2f} km/h")
        except:
            messagebox.showerror("错误", f"速度计算失败")

    
    def generate_srt(self):
        if self.gpx_data:
            try:
                srt_list = gf.gpx_to_srt(self.gpx_data)
                srt_path = self.srt_entry.get()
                if srt_path:
                    gf.save_lines(srt_list, srt_path)
                    messagebox.showinfo("SRT生成", f"SRT文件已保存: {srt_path}")
            except Exception as e:
                messagebox.showerror("错误", f"生成SRT文件失败: {e}")
    
    def save_files(self):
        if self.gpx_data and self.output_entry.get():
            gf.save_lines(self.gpx_data, self.output_entry.get())
            messagebox.showinfo("保存", f"GPX文件已保存: {self.output_entry.get()}")
    
    def show_param_dialog(self, title, fields, callback):
        if not self.gpx_data:
            messagebox.showwarning("警告", "请先选择并加载GPX文件")
            return
        
        dialog = tk.Toplevel(self.root)
        dialog.title(title)
        dialog.geometry("400x300")
        self.center_window(dialog)  # 添加子窗口居中
        dialog.transient(self.root)
        dialog.grab_set()
        
        entries = []
        for i, (label, default) in enumerate(fields):
            tk.Label(dialog, text=label).grid(row=i, column=0, padx=10, pady=5, sticky="e")
            entry = tk.Entry(dialog)
            entry.insert(0, default)
            entry.grid(row=i, column=1, padx=10, pady=5)
            entries.append(entry)
        
        def apply_changes():
            try:
                params = [entry.get() for entry in entries]
                self.gpx_data = callback(params)
                dialog.destroy()
                self.status_label.config(text=f"{title}操作完成")
            except Exception as e:
                messagebox.showerror("错误", f"操作失败: {e}")
        
        tk.Button(dialog, text="确定", command=apply_changes).grid(row=len(fields), column=1, columnspan=2, pady=10)
        tk.Button(dialog, text="取消", command=dialog.destroy).grid(row=len(fields), column=2, columnspan=2, pady=10)

if __name__ == "__main__":
    root = tk.Tk()
    app = GPXEditor(root)
    root.mainloop()
    os._exit(0)

